package com.tom.redis.train;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ZParams;

import java.util.*;

/**
 * redis实战书第一章的代码练习
 *
 * @author yanghongjun19
 * @date 2020/12/20 12:38
 **/
public class Chapter01 {

    public static Jedis jedis;

    private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
    private static final int VOTE_SCORE = 1;
    private static final int ARTICLES_PER_PAGE = 10;

    private static final String IT_TYPE = "it";
    private static final String BANK_TYPE = "bank";
    private static final String[] ARTICLE_GROUP = {IT_TYPE, BANK_TYPE};

    public static void main(String[] args) {

        jedis = new Jedis("127.0.0.1", 7000);

        //1:发布文章
        String article1 = postArticle("tom", "spring在企业中的应用", "http://spring.io", "100");
        String article2 = postArticle("tom", "redis实战", "http://redis.io", "100");

        String article3 = postArticle("yang", "房价还能涨多久", "www.sohu.com", "101");
        String article4 = postArticle("yang", "地产的冬天要来了", "www.sohu.com", "101");


        //2:投票
        articleVote(article1, "110");
        articleVote(article2, "110");
        articleVote(article3, "110");

        articleVote(article1, "111");
        articleVote(article4, "111");

        //3:获取文章列表
        List<Map<String, String>> scoreArticles = getArticles(1, "article:score");

        System.out.println("按照分数排名的文章=====");
        for (Map<String, String> article : scoreArticles) {
            System.out.println(article.toString());
        }

        //4:文章加入分组

        addGroups(article1, new String[]{IT_TYPE});
        addGroups(article2, new String[]{IT_TYPE});

        addGroups(article3, new String[]{BANK_TYPE});
        addGroups(article4, new String[]{BANK_TYPE});

        //5:获取特定分组的文章

        List<Map<String, String>> groupList = fetchGroupArticle(IT_TYPE, 1, "article:score");

        System.out.println("按照it类分组=====");
        for (Map<String, String> article : groupList) {
            System.out.println(article.toString());
        }


    }


    /**
     * 发布文章
     *
     * @param userName 作者姓名
     * @param title    文章title
     * @param link     文章链接
     * @param userId   作者id
     * @return 文章id
     */
    public static String postArticle(String userName, String title, String link, String userId) {

        //1:获取文章id
        Long articleId = jedis.incr("article:id");
        long now = System.currentTimeMillis() / 1000;
        String article = "article:" + articleId;

        //2:发布文章
        HashMap<String, String> articleData = new HashMap<>(10);
        articleData.put("title", title);
        articleData.put("link", link);
        articleData.put("now", String.valueOf(now));
        articleData.put("userName", userName);
        articleData.put("userId", userId);
        articleData.put("votes", "1");
        jedis.hmset(article, articleData);

        //3: 把作者加入投票集合
        String voted = "voted:" + articleId;
        jedis.sadd(voted, userId);
        jedis.expire(voted, ONE_WEEK_IN_SECONDS);

        //4:添加文章的得分及发布时间有序集合
        jedis.zadd("article:score", VOTE_SCORE, article);
        jedis.zadd("article:time", now, article);
        return String.valueOf(articleId);
    }

    /**
     * 给文章投票
     *
     * @param articleId 文章id
     * @param userId    用户id
     */
    public static void articleVote(String articleId, String userId) {

        String voted = "voted:" + articleId;

        //1:判断投票过期了
        long cutOff = System.currentTimeMillis() / 1000 - ONE_WEEK_IN_SECONDS;
        if (jedis.zscore("article:time", "article:" + articleId) < cutOff) {
            return;
        }

        //2:开始投票
        if (jedis.sadd(voted, userId) == 1) {
            //3:更改得分
            jedis.zincrby("article:score", VOTE_SCORE, "article:" + articleId);
            //4:更改文章投票数
            jedis.hincrBy("article:" + articleId, "votes", 1);
        }
    }


    /**
     * 把文章加入群组
     *
     * @param articleId 文章id
     * @param toAdd     群分组
     */
    public static void addGroups(String articleId, String[] toAdd) {

        String article = "article:" + articleId;

        //1:先把当前的文章的之前分组删除
        for (String type : ARTICLE_GROUP) {
            jedis.srem("group:" + type, article);
        }
        //2:添加新的分组
        for (String group : toAdd) {
            jedis.sadd("group:" + group, article);
        }
        jedis.srem("", articleId);
    }


    /**
     * 分页获取文章列表
     *
     * @param page  当前页
     * @param order 类型
     * @return 文章list
     */
    public static List<Map<String, String>> getArticles(int page, String order) {

        int start = (page - 1) * ARTICLES_PER_PAGE;
        int end = start + ARTICLES_PER_PAGE - 1;

        Set<String> articles = jedis.zrevrange(order, start, end);
        List<Map<String, String>> articleList = new ArrayList<>();
        for (String article : articles) {
            articleList.add(jedis.hgetAll(article));
        }

        return articleList;
    }

    /**
     * 获取分组的文章
     *
     * @param group 组类型
     * @param page  当前页
     * @param order 发布时间或者得分
     * @return 文章list
     */
    public static List<Map<String, String>> fetchGroupArticle(String group, int page, String order) {
        String key = order + ":" + group;
        if (!jedis.exists(key)) {
            ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX);
            jedis.zinterstore(key, params, "group:" + group, order);
            jedis.expire(key, 60);
        }
        return getArticles(page, key);
    }

}
